
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <fcntl.h>
#include <unistd.h>

#include <libifconfig.h>

#include <libepoll.h>

#define SERVER_IP					"104.224.129.80"
//#define SERVER_IP					"10.10.10.6"
#define FILE_MAX_LEN				1024

enum client_type
{
	CLIENT_TYPE_NORMAL = 0,

	CLIENT_TYPE_PIPE,

	CLIENT_TYPE_TCP_BUTT
};

static struct client_list
{
	enum client_type type;

	int pipe_fd;
} handle_list[FILE_MAX_LEN];

static int connect_to(const char *addr, unsigned short port)
{
	int server_fd = -1;

	struct sockaddr_in server_addr;

	if(NULL == addr || 0 == port)
	{
		goto out;
	}

	server_fd = socket(AF_INET, SOCK_STREAM, 0);

	if(0 > server_fd)
	{
		goto out;
	}

	memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(port);
	server_addr.sin_addr.s_addr = inet_addr(addr);

	if(0 != connect(server_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)))
	{
		goto out1;
	}

	goto out;

out1:
	if(0 <= server_fd)
	{
		close(server_fd);
		server_fd = -1;
	}
out:
	return server_fd;
}

static int config_new_link(Lib_Epoll *epoll, const char *addr, unsigned short port, enum client_type type = CLIENT_TYPE_NORMAL, int pipe = -1)
{
	int fd = -1;

	if(CLIENT_TYPE_PIPE == type)
	{
		if(0 > pipe)
		{
			goto out;
		}
	}

	fd = connect_to(addr, port);

	if(0 > fd)
	{
		goto out;
	}

	if(true != epoll->add(fd))
	{
		goto out1;
	}

	handle_list[fd].type = type;
	handle_list[fd].pipe_fd = pipe;

	goto out;

out1:
	close(fd);
	fd = -1;
out:
	return fd;
}

static void destroy_link(Lib_Epoll *epoll, int fd)
{
	handle_list[fd].type = CLIENT_TYPE_NORMAL;
	handle_list[fd].pipe_fd = -1;

	epoll->del(fd);

	close(fd);
	fd = -1;
}

static void handle_socket(void *arg, int fd)
{
	Lib_Epoll *epoll = (Lib_Epoll *)arg;

	int ret = 0;

	char buffer[2048] = {0};

	int client_new = 0;
	int server_new = 0;

	//printf("回调函数已进入，当前fd的类型为%d\n", handle_list[fd].type);

	switch(handle_list[fd].type)
	{
		case CLIENT_TYPE_NORMAL:
			ret = ::recv(fd, buffer, sizeof(buffer), 0);

			if(0 < ret)
			{
				printf("客户端已绑定，建立新的监听端\n");
				server_new = config_new_link(epoll, SERVER_IP, 5173);

				if(0 <= server_new)
				{
					printf("新的监听端已经建立成功，配置服务器\n");
					::send(server_new, "12345678", 8, 0);
				}

				printf("收到数据，长度为%d\n", ret);

				printf("开始建立对端连接\n");
				client_new = config_new_link(epoll, "192.168.10.102", 80, CLIENT_TYPE_PIPE, fd);

				if(0 <= client_new)
				{
					handle_list[fd].type = CLIENT_TYPE_PIPE;
					handle_list[fd].pipe_fd = client_new;

					printf("对端连接建立成功，发送数据，长度为%d\n", ret);

					::send(client_new, buffer, ret, 0);
				}
				else
				{
					printf("建立对端连接失败，销毁\n");

					destroy_link(epoll, fd);
				}
			}
			else
			{
				printf("接收数据失败，销毁\n");
				destroy_link(epoll, fd);

				printf("建立新的监听端\n");
				server_new = config_new_link(epoll, SERVER_IP, 5173);

				if(0 <= server_new)
				{
					printf("新的监听端已经建立成功，配置服务器\n");
					::send(server_new, "12345678", 8, 0);
				}
			}
			break;
		case CLIENT_TYPE_PIPE:
			ret = ::recv(fd, buffer, sizeof(buffer), 0);

			if(0 < ret)
			{
				//printf("收到对端连接数据，长度为%d\n", ret);
				if(0 <= handle_list[fd].pipe_fd)
				{
					//printf("转发对端连接数据，长度为%d\n", ret);
					::send(handle_list[fd].pipe_fd, buffer, ret, 0);
				}
				else
				{
					printf("对端连接转发出现异常，数据长度为%d，销毁\n", ret);
					destroy_link(epoll, fd);
				}
			}
			else
			{
				printf("接收对端连接数据失败，销毁\n");
				if(0 <= handle_list[fd].pipe_fd)
				{
					printf("销毁对端连接，对端\n");
					destroy_link(epoll, handle_list[fd].pipe_fd);
				}

				printf("销毁对端连接，本端\n");
				destroy_link(epoll, fd);
			}
			break;
		default:
			break;
	}
}

int main(int argc, char **argv)
{
	Lib_Epoll *epoll = NULL;

	int fd = 0;

	for(unsigned int i = 0; sizeof(handle_list) / sizeof(handle_list[0]) > i; i++)
	{
		handle_list[i].type = CLIENT_TYPE_NORMAL;
		handle_list[i].pipe_fd = -1;
	}

	epoll = Lib_Epoll::getObject(512);

	if(NULL == epoll)
	{
		goto out;
	}

	for(int i = 0; 10 > i; i++)
	{
		printf("建立新的监听端%d\n", i);

		fd = config_new_link(epoll, SERVER_IP, 5173);

		if(0 > fd)
		{
			goto out1;
		}

		printf("新的监听端%d已经建立成功，配置服务器\n", i);

		if(0 >= ::send(fd, "12345678", 8, 0))
		{
			goto out2;
		}
	}

	while(1)
	{
		epoll->wait(1000, handle_socket, epoll);
	}

out2:
	destroy_link(epoll, fd);
out1:
	delete epoll;
	epoll = NULL;
out:
	return 0;
}
